#ifndef THREADPOOL_H
#define THREADPOOL_H

#include <vector>
#include <mutex>
#include <condition_variable>
#include <memory>
#include <queue>
#include <atomic>
#include <functional>
#include <thread>
#include <unordered_map>

class Any
{
public:
    Any() = default;
    ~Any() = default;
    Any(const Any &) = delete;
    Any &operator=(const Any &) = delete;

    Any(Any &&) = default;
    Any &operator=(Any &&) = default;

    template <class T>
    Any(T data) : base_(std::make_unique<Derive<T>>(data))
    {
    }

    template <class T>
    T cast_()
    {
        Derive<T> *pd = dynamic_cast<Derive<T> *>(base_.get());
        if (pd == nullptr)
        {
            throw "type is unmatch";
        }
        return pd->data_;
    }

private:
    class Base
    {
    public:
        virtual ~Base() = default;
    };
    template <class T>
    class Derive : public Base
    {
    public:
        Derive(T data) : data_(data) {}
        ~Derive() {}
        T data_;
    };

private:
    std::unique_ptr<Base> base_;
};

class Semaphore
{
public:
    Semaphore(int limit = 0)
        : resLimit_(limit)
    {
    }

    void wait()
    {
        std::unique_lock<std::mutex> lock(mtx_);
        cond_.wait(lock, [&]() -> bool
                   { return resLimit_ > 0; });
        resLimit_--;
    }
    void post()
    {
        std::unique_lock<std::mutex> lock(mtx_);
        resLimit_++;
        cond_.notify_all();
    }

private:
    int resLimit_;
    std::mutex mtx_;
    std::condition_variable cond_;
};

class Task;
class Result
{
public:
    Result(std::shared_ptr<Task> task, bool isValid = true);
    ~Result() = default;

    void setVal(Any any);

    Any get();

private:
    Any any_;
    Semaphore sem_;
    std::shared_ptr<Task> task_;
    std::atomic_bool isValid_;
};

class Task
{
public:
    Task();
    ~Task() = default;

    void setResult(Result *res);

    virtual Any run() = 0;
    void exec();

private:
    Result *result_;
};

enum class PoolMode
{
    MODE_FIXED,
    MODE_CACHED
};

class Thread
{
public:
    using ThreadFunc = std::function<void(int)>;

    Thread(ThreadFunc func);

    ~Thread();

    void start();

    int getId() const;

private:
    ThreadFunc func_;
    int threadId_;
    static int generateId_;
};

class ThreadPool
{
public:
    ThreadPool();
    ~ThreadPool();

    void setMode(PoolMode poolmode);

    void setTaskQueMaxThreshHold(int threshHold);

    Result submitTask(std::shared_ptr<Task> sp);

    void start(int initThreadSize = std::thread::hardware_concurrency());

    void setThreadSizeThreshHold(int threshhold);

    ThreadPool(const ThreadPool &) = delete;
    ThreadPool &operator=(const ThreadPool &) = delete;

private:
    void threadFunc(int threadid);
    bool checkRunningState() const;

private:
    std::unordered_map<int, std::unique_ptr<Thread>> threads_; // 线程列表
    PoolMode poolMode_;                                        // 线程池工作模式

    // std::vector<std::unique_ptr<Thread>> threads_; // 线程列表
    size_t initThreadSize_;    // 初始化线程数量
    int threadSizeThreshHold_; // 线程上限数量
    std::atomic_int curThreadSize_;
    std::atomic_int idleThreadSize_; // 记录当前空闲线程的数量

    std::queue<std::shared_ptr<Task>> TaskQue_;
    std::atomic_uint TaskSize_; // 任务数量
    int taskQueMaxThreadHold_;  // 任务队列数量上线阈值

    std::mutex taskQueMtx_;            // 保证任务队列的线程安全
    std::condition_variable notFull_;  // 任务队列不空
    std::condition_variable notEmpty_; // 任务队列不满
    std::condition_variable exitCond_; // 等待线程资源全部回收

    std::atomic_bool isPoolRunning_; // 当前线程池的状态
};

#endif
